﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public static class UvSphereTool
{
    /// <summary>
    /// 创建半径为1的球体网格
    /// </summary>
    /// <param name="segments">沿轴向细分数</param>
    /// <param name="rings">高度细分数</param>
    public static Mesh CreateUvSphere(int segments, int rings)
    => CreateUvSphere(0, Mathf.PI * 2, 0, Mathf.PI, segments, rings);

    /// <summary>
    /// 创建半径为1的部分球体网格
    /// </summary>
    /// <param name="startφ">起始方位角（弧度制）</param>
    /// <param name="endφ">结束方位角（弧度制）</param>
    /// <param name="startθ">起始天顶角（弧度制）</param>
    /// <param name="endθ">结束天顶角（弧度制）</param>
    /// <param name="segments">沿轴向细分数</param>
    /// <param name="rings">高度细分数</param>、
    public static Mesh CreateUvSphere(float startφ, float endφ, float startθ, float endθ, int segments, int rings)
    {
        Mesh mesh = new Mesh();
        mesh.name = "UV Sphere";

        //限定在合理数值区间内
        {
            startφ = Mathf.Clamp(startφ, 0, Mathf.PI * 2);
            endφ = Mathf.Clamp(endφ, startφ, Mathf.PI * 2);
            startθ = Mathf.Clamp(startθ, 0, Mathf.PI);
            endθ = Mathf.Clamp(endθ, startθ, Mathf.PI);

            segments = Mathf.Max(1, segments);
            rings = Mathf.Max(1, rings);
        }

        float θPerRing = (endθ - startθ) / rings;
        float φPerSegment = (endφ - startφ) / segments;

        int horizontal_count = segments + 1;
        int vertical_count = rings + 1;

        Vector3[] vertices = new Vector3[horizontal_count * vertical_count];
        Vector3[] normals = new Vector3[vertices.Length];
        Vector2[] uvs = new Vector2[vertices.Length];

        int[] tris = new int[segments * rings * 2 * 3];

        for (int v = 0; v < vertical_count; v++)
            for (int h = 0; h < horizontal_count; h++)
            {
                int index = v * horizontal_count + h;
                //首先绕X轴旋转获取正确的θ
                var θ = startθ + θPerRing * v;
                var positionRotateθ = new Vector3(
                    0,
                    Mathf.Cos(θ),
                    Mathf.Sin(θ)
                    );

                //然后绕y轴旋转获取正确的φ
                var φ = startφ + φPerSegment * h;
                var position = new Vector3(
                    positionRotateθ.z * Mathf.Sin(φ),
                    positionRotateθ.y,
                    positionRotateθ.z * Mathf.Cos(φ)
                    );


                vertices[index] = position;
                normals[index] = position;

                uvs[index] = GetUV(φ, θ);

                if (v < vertical_count - 1 && h < horizontal_count - 1)
                {
                    tris[6 * (v * (horizontal_count - 1) + h) + 0] = (v + 0) * horizontal_count + h + 0;
                    tris[6 * (v * (horizontal_count - 1) + h) + 1] = (v + 1) * horizontal_count + h + 0;
                    tris[6 * (v * (horizontal_count - 1) + h) + 2] = (v + 0) * horizontal_count + h + 1;
                    tris[6 * (v * (horizontal_count - 1) + h) + 3] = (v + 0) * horizontal_count + h + 1;
                    tris[6 * (v * (horizontal_count - 1) + h) + 4] = (v + 1) * horizontal_count + h + 0;
                    tris[6 * (v * (horizontal_count - 1) + h) + 5] = (v + 1) * horizontal_count + h + 1;

                }
            }


        mesh.vertices = vertices;
        mesh.normals = normals;
        mesh.uv = uvs;
        mesh.triangles = tris;

        mesh.RecalculateBounds();
        return mesh;
    }

    static Vector2 GetUV(float φ, float θ)
    {
        return new Vector2(1 - φ/Mathf.PI/2, 1 - θ/Mathf.PI);
    }
}
